import { Player, Match, Hero, PlayerStats, MatchDetail, LeagueSearchResult, LeagueDetail, LeagueMatch, PlayerPerformanceStats, LeaguePlayerRanking, VisionMasterRanking, VisionMasterStats, KillingMachineRanking, KillingMachineStats } from '@/types/dota'
import { cacheManager } from './cacheManager'

const OPENDOTA_API_BASE = 'https://api.opendota.com/api'
const STRATZ_API_BASE = 'https://api.stratz.com/graphql'

// 默认的STRATZ API token（作为备用）
const DEFAULT_STRATZ_API_TOKEN = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJTdWJqZWN0IjoiNTYyN2NkNDItMjg2ZC00YTVlLTk1YzEtNWMyOGZiZjA2MTE2IiwiU3RlYW1JZCI6IjEwMTE3NDEzNyIsIkFQSVVzZXIiOiJ0cnVlIiwibmJmIjoxNzU4NzYyNjMwLCJleHAiOjE3OTAyOTg2MzAsImlhdCI6MTc1ODc2MjYzMCwiaXNzIjoiaHR0cHM6Ly9hcGkuc3RyYXR6LmNvbSJ9.x4MCCqqhuCPp9l3dpZv8r4f7X8b4lfn9xcBUi16kx98'

// 获取用户设置的API key或使用默认值
const getStratzApiToken = (): string => {
  const userApiKey = localStorage.getItem('stratz_api_key');
  return userApiKey && userApiKey.trim() ? userApiKey.trim() : DEFAULT_STRATZ_API_TOKEN;
}

class OpenDotaAPI {
  // 缓存机制
  private matchDetailCache = new Map<string, { data: MatchDetail; timestamp: number }>()
  private readonly CACHE_DURATION = 5 * 60 * 1000 // 5分钟缓存
  
  // 新增：智能缓存机制，避免重复获取相同比赛详情
  private leagueMatchCache = new Map<string, { data: MatchDetail; timestamp: number }>()
  private readonly LEAGUE_CACHE_DURATION = 10 * 60 * 1000 // 10分钟缓存

  private getCachedLeagueMatch(matchId: string): MatchDetail | null {
    const cached = this.leagueMatchCache.get(matchId)
    if (cached && Date.now() - cached.timestamp < this.LEAGUE_CACHE_DURATION) {
      return cached.data
    }
    return null
  }

  private setCachedLeagueMatch(matchId: string, data: MatchDetail) {
    this.leagueMatchCache.set(matchId, { data, timestamp: Date.now() })
    
    // 清理过期缓存
    if (this.leagueMatchCache.size > 500) {
      const now = Date.now()
      for (const [key, value] of this.leagueMatchCache.entries()) {
        if (now - value.timestamp > this.LEAGUE_CACHE_DURATION) {
          this.leagueMatchCache.delete(key)
        }
      }
    }
  }
  
  // API状态跟踪
  private openDotaFailureCount = 0
  private stratzFailureCount = 0
  private lastOpenDotaFailure = 0
  private lastStratzFailure = 0
  private readonly FAILURE_THRESHOLD = 3 // 连续失败阈值
  private readonly COOLDOWN_PERIOD = 5 * 60 * 1000 // 5分钟冷却期
  private openDotaRateLimited = false // 标记OpenDota是否已被限流

  // STRATZ API 速率限制管理器
  private stratzRateLimiter = {
    // 根据STRATZ API文档的限制：默认令牌 20/秒, 250/分钟, 2000/小时, 10000/天
    limits: {
      perSecond: 18, // 保守设置，留2个请求的缓冲
      perMinute: 240, // 保守设置，留10个请求的缓冲
      perHour: 1900,  // 保守设置，留100个请求的缓冲
      perDay: 9500    // 保守设置，留500个请求的缓冲
    },
    
    // 请求计数器
    counters: {
      second: { count: 0, resetTime: 0 },
      minute: { count: 0, resetTime: 0 },
      hour: { count: 0, resetTime: 0 },
      day: { count: 0, resetTime: 0 }
    },
    
    // 请求队列
    queue: [] as Array<{
      resolve: (value: any) => void;
      reject: (reason: any) => void;
      request: () => Promise<any>;
      priority: number;
    }>,
    
    processing: false,
    
    // 重置计数器
    resetCounters() {
      const now = Date.now()
      
      if (now >= this.counters.second.resetTime) {
        this.counters.second.count = 0
        this.counters.second.resetTime = now + 1000
      }
      
      if (now >= this.counters.minute.resetTime) {
        this.counters.minute.count = 0
        this.counters.minute.resetTime = now + 60000
      }
      
      if (now >= this.counters.hour.resetTime) {
        this.counters.hour.count = 0
        this.counters.hour.resetTime = now + 3600000
      }
      
      if (now >= this.counters.day.resetTime) {
        this.counters.day.count = 0
        this.counters.day.resetTime = now + 86400000
      }
    },
    
    // 检查是否可以发送请求
    canMakeRequest(): boolean {
      this.resetCounters()
      
      return (
        this.counters.second.count < this.limits.perSecond &&
        this.counters.minute.count < this.limits.perMinute &&
        this.counters.hour.count < this.limits.perHour &&
        this.counters.day.count < this.limits.perDay
      )
    },
    
    // 增加请求计数
    incrementCounters() {
      this.counters.second.count++
      this.counters.minute.count++
      this.counters.hour.count++
      this.counters.day.count++
    },
    
    // 计算下次可以请求的时间
    getNextAvailableTime(): number {
      this.resetCounters()
      
      const delays = []
      
      if (this.counters.second.count >= this.limits.perSecond) {
        delays.push(this.counters.second.resetTime - Date.now())
      }
      
      if (this.counters.minute.count >= this.limits.perMinute) {
        delays.push(this.counters.minute.resetTime - Date.now())
      }
      
      if (this.counters.hour.count >= this.limits.perHour) {
        delays.push(this.counters.hour.resetTime - Date.now())
      }
      
      if (this.counters.day.count >= this.limits.perDay) {
        delays.push(this.counters.day.resetTime - Date.now())
      }
      
      return Math.max(0, ...delays)
    },
    
    // 处理请求队列
    async processQueue() {
      if (this.processing || this.queue.length === 0) return
      
      this.processing = true
      
      while (this.queue.length > 0) {
        if (!this.canMakeRequest()) {
          const delay = this.getNextAvailableTime()
          if (delay > 0) {
            console.log(`STRATZ API 速率限制，等待 ${delay}ms`)
            await new Promise(resolve => setTimeout(resolve, delay))
            continue
          }
        }
        
        // 按优先级排序（数字越小优先级越高）
        this.queue.sort((a, b) => a.priority - b.priority)
        
        const item = this.queue.shift()!
        this.incrementCounters()
        
        try {
          const result = await item.request()
          item.resolve(result)
        } catch (error) {
          item.reject(error)
        }
        
        // 请求间的最小间隔（避免突发请求）
        await new Promise(resolve => setTimeout(resolve, 60)) // 60ms间隔，确保不超过16.7/秒
      }
      
      this.processing = false
    },
    
    // 添加请求到队列
    async enqueueRequest<T>(request: () => Promise<T>, priority: number = 5): Promise<T> {
      return new Promise((resolve, reject) => {
        this.queue.push({ resolve, reject, request, priority })
        this.processQueue()
      })
    }
  }

  // 检查API是否可用
  private isApiAvailable(apiType: 'opendota' | 'stratz'): boolean {
    const now = Date.now()
    
    if (apiType === 'opendota') {
      // 如果OpenDota已被标记为限流，则不可用
      if (this.openDotaRateLimited) {
        return false
      }
      // 如果连续失败次数超过阈值且在冷却期内，则认为不可用
      return this.openDotaFailureCount < this.FAILURE_THRESHOLD || 
             (now - this.lastOpenDotaFailure) > this.COOLDOWN_PERIOD
    } else {
      return this.stratzFailureCount < this.FAILURE_THRESHOLD || 
             (now - this.lastStratzFailure) > this.COOLDOWN_PERIOD
    }
  }

  // 记录API成功
  private recordApiSuccess(apiType: 'opendota' | 'stratz') {
    if (apiType === 'opendota') {
      this.openDotaFailureCount = 0
    } else {
      this.stratzFailureCount = 0
    }
  }

  // 记录API失败
  private recordApiFailure(apiType: 'opendota' | 'stratz', is429Error: boolean = false) {
    const now = Date.now()
    
    if (apiType === 'opendota') {
      this.openDotaFailureCount++
      this.lastOpenDotaFailure = now
      // 如果是429错误，标记OpenDota为限流状态
      if (is429Error) {
        this.openDotaRateLimited = true
        console.log('OpenDota API已被标记为限流状态，后续请求将使用STRATZ API')
      }
      if (this.openDotaFailureCount >= this.FAILURE_THRESHOLD) {
        console.warn(`OpenDota API连续失败${this.openDotaFailureCount}次，进入冷却期`)
      }
    } else {
      this.stratzFailureCount++
      this.lastStratzFailure = now
      if (this.stratzFailureCount >= this.FAILURE_THRESHOLD) {
        console.warn(`STRATZ API连续失败${this.stratzFailureCount}次，进入冷却期`)
      }
    }
  }

  // 获取推荐的API源
  private getPreferredApiSource(): 'opendota' | 'stratz' {
    // 如果OpenDota已被限流，直接使用STRATZ
    if (this.openDotaRateLimited) {
      return 'stratz'
    }
    
    const openDotaAvailable = this.isApiAvailable('opendota')
    const stratzAvailable = this.isApiAvailable('stratz')
    
    // 如果OpenDota可用，优先使用OpenDota
    if (openDotaAvailable) {
      return 'opendota'
    }
    
    // 如果OpenDota不可用但STRATZ可用，使用STRATZ
    if (stratzAvailable) {
      console.log('OpenDota API不可用，切换到STRATZ API')
      return 'stratz'
    }
    
    // 如果都不可用，仍然返回OpenDota（让错误正常抛出）
    console.warn('所有API都不可用，尝试使用OpenDota API')
    return 'opendota'
  }

  // OpenDota API 基础请求方法
  private async fetchAPI(endpoint: string): Promise<any> {
    const response = await fetch(`${OPENDOTA_API_BASE}${endpoint}`)
    if (!response.ok) {
      throw new Error(`API请求失败: ${response.status} ${response.statusText}`)
    }
    return response.json()
  }

  // STRATZ API GraphQL 查询方法
  private async fetchStratzAPI(query: string, variables?: any): Promise<any> {
    try {
      const apiToken = getStratzApiToken();
      const requestBody = {
        query,
        variables
      };
      
      console.log('STRATZ API请求详情:', {
        url: STRATZ_API_BASE,
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${apiToken.substring(0, 20)}...`,
          'User-Agent': 'STRATZ_API'
        },
        body: requestBody
      });

      const response = await fetch(STRATZ_API_BASE, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${apiToken}`,
          'User-Agent': 'STRATZ_API'
        },
        body: JSON.stringify(requestBody)
      })

      console.log('STRATZ API响应状态:', response.status, response.statusText);

      if (!response.ok) {
        // 尝试读取响应体以获取更多错误信息
        let errorBody = '';
        try {
          errorBody = await response.text();
          console.error('STRATZ API错误响应体:', errorBody);
        } catch (e) {
          console.error('无法读取错误响应体:', e);
        }
        throw new Error(`STRATZ API请求失败: ${response.status} ${response.statusText}${errorBody ? ` - ${errorBody}` : ''}`)
      }

      const data = await response.json()
      console.log('STRATZ API响应数据:', data);
      
      if (data.errors) {
        console.error('STRATZ API GraphQL错误:', data.errors);
        throw new Error(`STRATZ API错误: ${data.errors.map((e: any) => e.message).join(', ')}`)
      }

      return data.data
    } catch (error) {
      console.error('STRATZ API请求失败:', error)
      throw error
    }
  }

  // 使用STRATZ API获取联赛比赛数据
  private async getLeagueMatchesFromStratz(leagueId: number, page: number = 0, pageSize: number = 50): Promise<LeagueMatch[]> {
    // STRATZ API 限制最大 take 值为 100
    const limitedPageSize = Math.min(pageSize, 100)
    const skip = page * limitedPageSize
    const query = `
      query GetLeagueMatches($leagueId: Int!, $take: Int!, $skip: Int!) {
        league(id: $leagueId) {
          id
          displayName
          matches(request: { take: $take, skip: $skip }) {
            id
            startDateTime
            durationSeconds
            didRadiantWin
            radiantTeam {
              id
              name
            }
            direTeam {
              id
              name
            }
            radiantKills
            direKills
          }
        }
      }
    `

    try {
      const data = await this.fetchStratzAPI(query, { leagueId, take: limitedPageSize, skip })
      
      if (!data.league || !data.league.matches) {
        console.log(`STRATZ API: 联赛 ${leagueId} 没有找到比赛数据`)
        return []
      }

      return data.league.matches.map((match: any): LeagueMatch => ({
        match_id: match.id,
        league_id: leagueId,
        start_time: match.startDateTime,
        duration: match.durationSeconds,
        radiant_team: match.radiantTeam ? {
          team_id: match.radiantTeam.id || 0,
          name: match.radiantTeam.name || 'Radiant',
          tag: match.radiantTeam.tag || '',
          logo_url: match.radiantTeam.logo || null
        } : undefined,
        dire_team: match.direTeam ? {
          team_id: match.direTeam.id || 0,
          name: match.direTeam.name || 'Dire',
          tag: match.direTeam.tag || '',
          logo_url: match.direTeam.logo || null
        } : undefined,
        radiant_score: match.radiantKills || 0,
        dire_score: match.direKills || 0,
        radiant_win: match.didRadiantWin,
        game_mode: match.gameMode,
        lobby_type: match.lobbyType,
        series_id: match.seriesId,
        series_type: match.seriesType
      }))
    } catch (error) {
      console.error('STRATZ API 获取联赛比赛失败:', error)
      throw error
    }
  }

  // 获取玩家基本信息
  async getPlayer(accountId: string): Promise<Player> {
    return this.fetchAPI(`/players/${accountId}`)
  }

  // 获取玩家最近比赛
  async getPlayerMatches(accountId: string, limit: number = 20): Promise<Match[]> {
    return this.fetchAPI(`/players/${accountId}/matches?limit=${limit}`)
  }

  // 获取玩家统计数据
  async getPlayerStats(accountId: string): Promise<PlayerStats> {
    return this.fetchAPI(`/players/${accountId}`)
  }

  // 获取所有英雄数据
  async getHeroes(): Promise<Hero[]> {
    return this.fetchAPI('/heroes')
  }

  // 获取玩家英雄统计
  async getPlayerHeroes(accountId: string): Promise<any[]> {
    return this.fetchAPI(`/players/${accountId}/heroes`)
  }

  // 获取比赛详情
  async getMatchDetail(matchId: string): Promise<MatchDetail> {
    // 检查缓存
    const cached = this.matchDetailCache.get(matchId)
    if (cached && Date.now() - cached.timestamp < this.CACHE_DURATION) {
      console.log(`使用缓存数据: ${matchId}`)
      return cached.data
    }

    const data = await this.fetchAPI(`/matches/${matchId}`)
    
    // 存储到缓存
    this.matchDetailCache.set(matchId, {
      data,
      timestamp: Date.now()
    })
    
    // 清理过期缓存（避免内存泄漏）
    this.cleanExpiredCache()
    
    return data
  }

  // 清理过期缓存
  private cleanExpiredCache() {
    const now = Date.now()
    for (const [key, value] of this.matchDetailCache.entries()) {
      if (now - value.timestamp >= this.CACHE_DURATION) {
        this.matchDetailCache.delete(key)
      }
    }
  }

  // 使用STRATZ API获取比赛详情
  private async getMatchDetailFromStratz(matchId: string): Promise<MatchDetail> {
    const query = `
      query GetMatchDetail($matchId: Long!) {
        match(id: $matchId) {
          id
          startDateTime
          durationSeconds
          didRadiantWin
          gameMode
          lobbyType
          firstBloodTime
          radiantKills
          direKills
          radiantNetworthLeads
          radiantExperienceLeads
          players {
            steamAccountId
            playerSlot
            heroId
            kills
            deaths
            assists
            networth
            numLastHits
            numDenies
            goldPerMinute
            experiencePerMinute
            level
            heroDamage
            towerDamage
            heroHealing
            item0Id
            item1Id
            item2Id
            item3Id
            item4Id
            item5Id
            backpack0Id
            backpack1Id
            backpack2Id
            stats {
              wards {
                time
                type
                positionX
                positionY
              }
            }
            steamAccount {
              name
              avatar
            }
          }
          pickBans {
            isPick
            heroId
            order
            bannedHeroId
            isRadiant
          }
        }
      }
    `

    try {
      const data = await this.fetchStratzAPI(query, { matchId: parseInt(matchId) })
      
      if (!data.match) {
        throw new Error(`STRATZ API: 比赛 ${matchId} 未找到`)
      }

      const match = data.match
      
      // 转换STRATZ数据格式为OpenDota格式
      const matchDetail: MatchDetail = {
        match_id: parseInt(matchId),
        barracks_status_dire: 0, // STRATZ API不提供此数据
        barracks_status_radiant: 0,
        cluster: 0,
        dire_score: match.direKills || 0,
        duration: match.durationSeconds || 0,
        engine: 1,
        first_blood_time: match.firstBloodTime || 0,
        game_mode: match.gameMode || 0,
        human_players: match.players?.length || 10,
        leagueid: 0, // 需要从其他地方获取
        lobby_type: match.lobbyType || 0,
        match_seq_num: 0,
        negative_votes: 0,
        positive_votes: 0,
        radiant_gold_adv: match.radiantNetworthLeads || [],
        radiant_score: match.radiantKills || 0,
        radiant_win: match.didRadiantWin || false,
        radiant_xp_adv: match.radiantExperienceLeads || [],
        start_time: match.startDateTime ? Math.floor(new Date(match.startDateTime).getTime() / 1000) : 0,
        tower_status_dire: 0,
        tower_status_radiant: 0,
        version: 0,
        replay_salt: 0,
        series_id: 0,
        series_type: 0,
        skill: 0,
        patch: 0,
        region: 0,
        players: match.players?.map((player: any) => ({
          match_id: parseInt(matchId),
          player_slot: player.playerSlot || 0,
          ability_upgrades_arr: [],
          account_id: player.steamAccountId || 0,
          assists: player.assists || 0,
          backpack_0: player.backpack0Id || 0,
          backpack_1: player.backpack1Id || 0,
          backpack_2: player.backpack2Id || 0,
          camps_stacked: 0,
          creeps_stacked: 0,
          deaths: player.deaths || 0,
          denies: player.numDenies || 0,
          gold: player.networth || 0,
          gold_per_min: player.goldPerMinute || 0,
          gold_spent: 0,
          hero_damage: player.heroDamage || 0,
          hero_healing: player.heroHealing || 0,
          hero_id: player.heroId || 0,
          item_0: player.item0Id || 0,
          item_1: player.item1Id || 0,
          item_2: player.item2Id || 0,
          item_3: player.item3Id || 0,
          item_4: player.item4Id || 0,
          item_5: player.item5Id || 0,
          kills: player.kills || 0,
          last_hits: player.numLastHits || 0,
          leaver_status: 0,
          level: player.level || 0,
          obs_placed: (() => {
            if (player.stats?.wards) {
              console.log('Ward data found for player:', player.steamAccount?.name || 'Unknown');
              console.log('Total wards:', player.stats.wards.length);
              console.log('Ward types:', player.stats.wards.map((w: any) => w.type));
              const obsCount = player.stats.wards.filter((ward: any) => ward.type === 0).length;
              console.log('Observer wards (type 0):', obsCount);
              return obsCount;
            } else {
              console.log('No ward data for player:', player.steamAccount?.name || 'Unknown');
              return 0;
            }
          })(),
          sen_placed: player.stats?.wards ? 
            player.stats.wards.filter((ward: any) => ward.type === 1).length : 0,
          stuns: 0,
          tower_damage: player.towerDamage || 0,
          xp_per_min: player.experiencePerMinute || 0,
          personaname: player.steamAccount?.name || `Player ${player.steamAccountId}`,
          name: player.steamAccount?.name,
          radiant_win: match.didRadiantWin || false,
          start_time: match.startDateTime ? Math.floor(new Date(match.startDateTime).getTime() / 1000) : 0,
          duration: match.durationSeconds || 0,
          cluster: 0,
          lobby_type: match.lobbyType || 0,
          game_mode: match.gameMode || 0,
          patch: 0,
          region: 0,
          isRadiant: (player.playerSlot || 0) < 128,
          win: (match.didRadiantWin && (player.playerSlot || 0) < 128) || (!match.didRadiantWin && (player.playerSlot || 0) >= 128) ? 1 : 0,
          lose: (match.didRadiantWin && (player.playerSlot || 0) >= 128) || (!match.didRadiantWin && (player.playerSlot || 0) < 128) ? 1 : 0,
          total_gold: player.networth || 0,
          total_xp: 0,
          kills_per_min: 0,
          kda: player.deaths > 0 ? (player.kills + player.assists) / player.deaths : (player.kills + player.assists),
          abandons: 0,
          neutral_kills: 0,
          tower_kills: 0,
          courier_kills: 0,
          lane_kills: 0,
          hero_kills: player.kills || 0,
          observer_kills: 0,
          sentry_kills: 0,
          roshan_kills: 0,
          necronomicon_kills: 0,
          ancient_kills: 0,
          buyback_count: 0,
          observer_uses: 0,
          sentry_uses: 0,
          lane_efficiency: 0,
          lane_efficiency_pct: 0,
          lane: 0,
          lane_role: 0,
          is_roaming: false,
          actions_per_min: 0,
          life_state_dead: 0,
          rank_tier: 0
        })) || [],
        picks_bans: match.pickBans?.map((pb: any) => ({
          is_pick: pb.isPick || false,
          hero_id: pb.heroId || pb.bannedHeroId || 0,
          team: pb.isRadiant ? 0 : 1,
          order: pb.order || 0
        })) || []
      }

      console.log(`STRATZ API成功获取比赛详情: ${matchId}`)
      return matchDetail
    } catch (error) {
      console.error(`STRATZ API获取比赛详情失败 (${matchId}):`, error)
      throw error
    }
  }

  // 获取比赛详情（带重试机制和STRATZ备用）
  async getMatchDetailWithRetry(matchId: string, maxRetries: number = 5): Promise<MatchDetail> {
    let lastOpenDotaError: any = null
    let lastStratzError: any = null
    
    // 获取首选API源
    const preferredApi = this.getPreferredApiSource()
    console.log(`获取比赛详情 ${matchId}，首选API: ${preferredApi}`)
    
    // 首先尝试首选API
    if (preferredApi === 'opendota' && this.isApiAvailable('opendota')) {
      for (let attempt = 1; attempt <= maxRetries; attempt++) {
        try {
          const result = await this.getMatchDetail(matchId)
          this.recordApiSuccess('opendota')
          console.log(`OpenDota API成功获取比赛详情: ${matchId}`)
          return result
        } catch (error: any) {
          lastOpenDotaError = error
          
          // 检查是否是429错误
          const is429Error = error.message?.includes('429')
          this.recordApiFailure('opendota', is429Error)
          
          // 如果是429错误，立即尝试STRATZ
          if (is429Error) {
            console.log(`OpenDota API被限流 (${matchId})，切换到STRATZ...`)
            break
          }
          
          if (attempt < maxRetries) {
            const delay = Math.min(1000 * Math.pow(2, attempt - 1), 8000)
            console.log(`OpenDota API请求失败 (${matchId})，第${attempt}次重试，等待${delay}ms...`)
            await new Promise(resolve => setTimeout(resolve, delay))
          }
        }
      }
    }
    
    // 尝试STRATZ API
    if (this.isApiAvailable('stratz')) {
      try {
        console.log(`尝试使用STRATZ API获取比赛详情: ${matchId}`)
        const stratzResult = await this.getMatchDetailFromStratz(matchId)
        this.recordApiSuccess('stratz')
        
        // 缓存STRATZ的结果
        this.matchDetailCache.set(matchId, {
          data: stratzResult,
          timestamp: Date.now()
        })
        
        console.log(`STRATZ API成功获取比赛详情: ${matchId}`)
        return stratzResult
      } catch (stratzError: any) {
        lastStratzError = stratzError
        this.recordApiFailure('stratz')
        console.error(`STRATZ API获取比赛详情失败 (${matchId}):`, stratzError)
      }
    }
    
    // 如果首选是STRATZ但失败了，再尝试OpenDota
    if (preferredApi === 'stratz' && this.isApiAvailable('opendota')) {
      for (let attempt = 1; attempt <= Math.min(maxRetries, 3); attempt++) {
        try {
          console.log(`STRATZ失败，尝试OpenDota API (${matchId})，第${attempt}次尝试`)
          const result = await this.getMatchDetail(matchId)
          this.recordApiSuccess('opendota')
          console.log(`OpenDota API成功获取比赛详情: ${matchId}`)
          return result
        } catch (error: any) {
          lastOpenDotaError = error
          
          // 检查是否是429错误
          const is429Error = error.message?.includes('429')
          this.recordApiFailure('opendota', is429Error)
          
          if (attempt < Math.min(maxRetries, 3)) {
            const delay = Math.min(1000 * Math.pow(2, attempt - 1), 4000)
            console.log(`OpenDota API请求失败 (${matchId})，第${attempt}次重试，等待${delay}ms...`)
            await new Promise(resolve => setTimeout(resolve, delay))
          }
        }
      }
    }
    
    // 所有API都失败了
    const errorMessage = `获取比赛详情失败 (${matchId}): ${
      lastOpenDotaError ? `OpenDota: ${lastOpenDotaError.message}` : ''
    }${lastOpenDotaError && lastStratzError ? ', ' : ''}${
      lastStratzError ? `STRATZ: ${lastStratzError.message}` : ''
    }`
    
    console.error(errorMessage)
    throw new Error(errorMessage)
  }

  // 搜索玩家
  async searchPlayers(query: string): Promise<any[]> {
    return this.fetchAPI(`/search?q=${encodeURIComponent(query)}`)
  }

  // 获取道具信息
  async getItems(): Promise<any> {
    return this.fetchAPI('/constants/items')
  }

  // 使用STRATZ API搜索联赛
  private async searchLeaguesFromStratz(query: string): Promise<LeagueSearchResult[]> {
    const graphqlQuery = `
      query SearchLeagues($request: LeagueRequestType!) {
        leagues(request: $request) {
          id
          displayName
          tier
          startDateTime
          endDateTime
          prizePool
          region
          imageUri
        }
      }
    `

    try {
      const data = await this.fetchStratzAPI(graphqlQuery, {
        request: {
          take: 50,
          skip: 0
        }
      })

      if (!data.leagues) {
        return []
      }

      // 过滤搜索结果
      const filteredLeagues = data.leagues.filter((league: any) => {
        const nameMatch = league.displayName?.toLowerCase().includes(query.toLowerCase())
        const idMatch = league.id?.toString().includes(query)
        return nameMatch || idMatch
      })

      return filteredLeagues.map((league: any) => {
        // 处理时间戳，确保格式正确
        let startTime = undefined
        let endTime = undefined
        
        if (league.startDateTime) {
          const startTimestamp = new Date(league.startDateTime).getTime()
          startTime = startTimestamp > 1000000000000 ? Math.floor(startTimestamp / 1000) : startTimestamp
        }
        
        if (league.endDateTime) {
          const endTimestamp = new Date(league.endDateTime).getTime()
          endTime = endTimestamp > 1000000000000 ? Math.floor(endTimestamp / 1000) : endTimestamp
        }
        
        const result = {
          leagueid: league.id,
          name: league.displayName || `League ${league.id}`,
          tier: this.mapStratzTier(league.tier) || 'unknown',
          banner: league.imageUri,
          start_time: startTime,
          end_time: endTime,
          prize_pool: league.prizePool,
          region: league.region
        }
        
        // 添加调试日志
        console.log(`联赛 ${result.name} 时间转换:`, {
          原始startDateTime: league.startDateTime,
          转换后start_time: result.start_time,
          转换后日期: result.start_time ? new Date(result.start_time * 1000) : null
        })
        
        return result
      })
    } catch (error) {
      console.error('STRATZ API搜索联赛失败:', error)
      return []
    }
  }

  // 映射STRATZ联赛等级到标准格式
  private mapStratzTier(tier: any): string {
    if (!tier) return 'unknown'
    
    switch (tier) {
      case 'PREMIUM':
        return 'premium'
      case 'PROFESSIONAL':
        return 'professional'
      case 'AMATEUR':
        return 'amateur'
      default:
        return 'unknown'
    }
  }

  // 搜索联赛 - 使用多数据源策略
  async searchLeagues(query: string): Promise<LeagueSearchResult[]> {
    try {
      console.log(`搜索联赛: ${query}`)
      
      let allResults: LeagueSearchResult[] = []
      
      // 策略1: 使用STRATZ API搜索
      console.log('尝试使用STRATZ API搜索联赛...')
      try {
        const stratzResults = await this.searchLeaguesFromStratz(query)
        if (stratzResults.length > 0) {
          console.log(`STRATZ API找到 ${stratzResults.length} 个联赛`)
          allResults = [...allResults, ...stratzResults]
        }
      } catch (stratzError) {
        console.warn('STRATZ API搜索失败:', stratzError)
      }

      // 策略2: 同时使用OpenDota API搜索
      console.log('使用OpenDota API搜索联赛...')
      try {
        const leagues = await this.fetchAPI('/leagues')
        
        // 模糊搜索联赛名称或ID
        const filteredLeagues = leagues.filter((league: any) => {
          const nameMatch = league.name?.toLowerCase().includes(query.toLowerCase())
          const idMatch = league.leagueid?.toString().includes(query)
          return nameMatch || idMatch
        })

        // 转换为搜索结果格式
        const openDotaResults = filteredLeagues.map((league: any) => ({
          leagueid: league.leagueid,
          name: league.name || `League ${league.leagueid}`,
          tier: league.tier || 'unknown',
          banner: league.banner,
          start_time: league.start_time,
          end_time: league.end_time,
          prize_pool: league.prize_pool,
          region: league.region
        }))

        console.log(`OpenDota API找到 ${openDotaResults.length} 个联赛`)
        allResults = [...allResults, ...openDotaResults]
      } catch (openDotaError) {
        console.warn('OpenDota API搜索失败:', openDotaError)
      }

      // 去重处理（基于leagueid）
      const uniqueResults = allResults.filter((league, index, self) => 
        index === self.findIndex(l => l.leagueid === league.leagueid)
      )

      console.log(`总共找到 ${uniqueResults.length} 个唯一联赛`)
      return uniqueResults
    } catch (error) {
      console.error('搜索联赛失败:', error)
      return []
    }
  }

  // 从OpenDota获取联赛时间信息
  private async getLeagueTimeFromOpenDota(leagueId: number): Promise<{start_time?: number, end_time?: number} | null> {
    try {
      const leagues = await this.fetchAPI('/leagues')
      const league = leagues.find((l: any) => l.leagueid === leagueId)
      
      if (league) {
        return {
          start_time: league.start_time,
          end_time: league.end_time
        }
      } else {
        console.log(`OpenDota中未找到联赛ID ${leagueId}`)
        return null
      }
    } catch (error) {
      console.error('从OpenDota获取联赛时间失败:', error)
      return null
    }
  }

  // 混合数据处理函数 - 使用STRATZ主要数据 + OpenDota时间数据
  private processLeagueData(stratzLeague: any, openDotaTime: {start_time?: number, end_time?: number} | null): LeagueDetail {
    const league = stratzLeague
    
    // 使用OpenDota的时间数据（如果可用），否则使用STRATZ的时间数据
    const startTime = openDotaTime?.start_time || league.startDateTime
    const endTime = openDotaTime?.end_time || league.endDateTime
    
    // 构建增强描述
    let enhancedDescription = league.description || ''
    
    // 添加统计信息
    if (league.stats?.matchCount) {
      enhancedDescription += (enhancedDescription ? '\n\n' : '') + `联赛统计: ${league.stats.matchCount} 场比赛`
    }
    
    // 添加地点信息
    if (league.venue || league.country) {
      const locationInfo = []
      if (league.venue) locationInfo.push(league.venue)
      if (league.country) locationInfo.push(league.country)
      
      if (locationInfo.length > 0) {
        enhancedDescription += (enhancedDescription ? '\n\n' : '') + `举办地点: ${locationInfo.join('，')}`
      }
    }
    
    // 添加时间数据来源信息
    const timeSource = openDotaTime ? 'OpenDota' : 'STRATZ'
    enhancedDescription += (enhancedDescription ? '\n\n' : '') + `时间数据来源: ${timeSource}`
    
    return {
      leagueid: league.id,
      name: league.displayName,
      tier: this.mapStratzTier(league.tier) || 'unknown',
      banner: league.imageUri,
      start_time: startTime ? (startTime > 1000000000000 ? Math.floor(startTime / 1000) : startTime) : undefined,
      end_time: endTime ? (endTime > 1000000000000 ? Math.floor(endTime / 1000) : endTime) : undefined,
      prize_pool: league.prizePool || 0,
      region: league.region,
      description: enhancedDescription || '暂无描述',
      organizer: league.venue || undefined,
      
      // STRATZ API 特有的额外字段
      venue: league.venue,
      country: league.country,
      stats: league.stats,
      nodeGroups: league.nodeGroups,
      liveMatches: league.liveMatches,
      streams: league.streams,
      
      // 时间数据来源标识
      timeSource: timeSource
    }
  }
  // 使用STRATZ API获取联赛详细信息 - 简化版本
  private async getLeagueDetailFromStratz(leagueId: number): Promise<any | null> {
    const query = `
      query GetLeagueDetail($id: Int!) {
        league(id: $id) {
          id
          displayName
          tier
          startDateTime
          endDateTime
          prizePool
          region
          imageUri
          venue
          country
          nodeGroups {
            id
            name
          }
          liveMatches {
            matchId
            createdDateTime
          }
          stats {
            matchCount
          }
          streams {
            name
            languageId
          }
        }
      }
    `

    try {
      const data = await this.fetchStratzAPI(query, { id: leagueId })
      
      if (!data.league) {
        return null
      }

      return data.league
    } catch (error) {
      console.error('STRATZ API获取联赛详情失败:', error)
      return null
    }
  }

  // 获取联赛详细信息 - 混合API策略
  async getLeagueDetail(leagueId: number): Promise<LeagueDetail | null> {
    // 首先检查缓存
    const cachedDetail = cacheManager.getLeagueDetail(leagueId)
    if (cachedDetail) {
      console.log(`从缓存获取联赛${leagueId}详情`)
      return cachedDetail
    }

    try {
      // 并行调用两个API
      const results = await Promise.allSettled([
        this.getLeagueDetailFromStratz(leagueId),
        this.getLeagueTimeFromOpenDota(leagueId)
      ])

      const stratzResult = results[0]
      const openDotaResult = results[1]

      // 检查STRATZ API结果
      let stratzData = null
      if (stratzResult.status === 'fulfilled' && stratzResult.value) {
        stratzData = stratzResult.value
        console.log('STRATZ API调用成功')
      } else {
        console.log('STRATZ API调用失败:', stratzResult.status === 'rejected' ? stratzResult.reason : 'No data')
      }

      // 检查OpenDota API结果
      let openDotaTimeData = null
      if (openDotaResult.status === 'fulfilled' && openDotaResult.value) {
        openDotaTimeData = openDotaResult.value
        console.log('OpenDota API调用成功')
      } else {
        console.log('OpenDota API调用失败:', openDotaResult.status === 'rejected' ? openDotaResult.reason : 'No data')
      }

      // 如果STRATZ API失败，尝试使用OpenDota API作为后备
      if (!stratzData) {
        console.log('STRATZ API失败，尝试使用OpenDota API作为后备')
        try {
          const leagues = await this.fetchAPI('/leagues')
          const league = leagues.find((l: any) => l.leagueid === leagueId)
          
          if (!league) {
            console.log(`联赛${leagueId}在OpenDota API中未找到`)
            return null
          }

          const openDotaDetail = {
            leagueid: league.leagueid,
            name: league.name || `League ${league.leagueid}`,
            tier: league.tier || 'unknown',
            banner: league.banner,
            start_time: league.start_time,
            end_time: league.end_time,
            prize_pool: league.prize_pool,
            region: league.region,
            description: league.description,
            organizer: league.organizer
          }

          console.log(`OpenDota API成功获取联赛${leagueId}详情`)
          return openDotaDetail
        } catch (error) {
          console.error('OpenDota API后备调用也失败:', error)
        }
        return null
      }

      // 使用混合数据处理函数
      const processedData = this.processLeagueData(stratzData, openDotaTimeData)
      
      // 输出详细信息（类似脚本输出）
      console.log('\n=== 联赛详细信息 ===')
      console.log('STRATZ API响应:', JSON.stringify(stratzData, null, 2))
      if (openDotaTimeData) {
        console.log('OpenDota API时间数据:', JSON.stringify(openDotaTimeData, null, 2))
      }
      console.log('处理后的联赛数据:', JSON.stringify(processedData, null, 2))
      
      // 输出摘要信息
      console.log('\n=== 联赛摘要 ===')
      console.log(`联赛名称: ${processedData.name}`)
      console.log(`联赛ID: ${processedData.leagueid}`)
      console.log(`等级: ${processedData.tier}`)
      console.log(`地区: ${processedData.region || '未知'}`)
      console.log(`奖金池: ${processedData.prize_pool ? `$${processedData.prize_pool.toLocaleString()}` : '未知'}`)
      console.log(`比赛数量: ${processedData.stats?.matchCount || 0}`)
      console.log(`时间数据来源: ${processedData.timeSource}`)
      if (processedData.start_time) {
        console.log(`开始时间: ${new Date(processedData.start_time * 1000).toLocaleString()}`)
      }
      if (processedData.end_time) {
        console.log(`结束时间: ${new Date(processedData.end_time * 1000).toLocaleString()}`)
      }

      // 将数据存储到缓存
      cacheManager.setLeagueDetail(leagueId, processedData)
      console.log(`联赛${leagueId}详情已缓存`)

      return processedData

    } catch (error) {
      console.error('获取联赛详情时发生错误:', error)
      return null
    }
  }

  // 获取联赛统计信息（天辉/夜魇胜利统计）
  async getLeagueStats(leagueId: number): Promise<{radiantWins: number, direWins: number, totalMatches: number}> {
    try {
      console.log(`获取联赛${leagueId}统计信息...`)
      
      // 使用STRATZ API获取联赛统计
      const query = `
        query GetLeagueStats($leagueId: Int!) {
          league(id: $leagueId) {
            id
            displayName
            stats {
              matchCount
            }
            matches(request: { take: 2000 }) {
              didRadiantWin
            }
          }
        }
      `

      try {
        const data = await this.fetchStratzAPI(query, { leagueId })
        
        if (data.league && data.league.matches) {
          const matches = data.league.matches
          const radiantWins = matches.filter((match: any) => match.didRadiantWin === true).length
          const direWins = matches.filter((match: any) => match.didRadiantWin === false).length
          const totalMatches = matches.length
          
          console.log(`联赛${leagueId}统计: 总计${totalMatches}场, 天辉${radiantWins}胜, 夜魇${direWins}胜`)
          
          return {
            radiantWins,
            direWins,
            totalMatches
          }
        }
      } catch (stratzError) {
        console.warn('STRATZ API获取统计失败:', stratzError)
      }

      // 如果STRATZ API失败，尝试从缓存或其他方式获取
      console.log('尝试从其他数据源获取统计...')
      
      // 尝试获取所有比赛数据来计算统计
      const allMatches: LeagueMatch[] = []
      const maxPages = 40 // 最多获取40页数据 (40 * 50 = 2000场比赛)
      
      for (let page = 0; page < maxPages; page++) {
        try {
          const pageMatches = await this.getLeagueMatches(leagueId, page, 50)
          if (pageMatches.length === 0) {
            break // 没有更多数据
          }
          allMatches.push(...pageMatches)
          
          // 如果这一页数据不足50条，说明已经是最后一页
          if (pageMatches.length < 50) {
            break
          }
        } catch (error) {
          console.warn(`获取第${page}页数据失败:`, error)
          break
        }
      }
      
      if (allMatches.length > 0) {
        const radiantWins = allMatches.filter(match => match.radiant_win === true).length
        const direWins = allMatches.filter(match => match.radiant_win === false).length
        const totalMatches = allMatches.length
        
        console.log(`通过分页获取联赛${leagueId}统计: 总计${totalMatches}场, 天辉${radiantWins}胜, 夜魇${direWins}胜`)
        
        return {
          radiantWins,
          direWins,
          totalMatches
        }
      }
      
      // 如果都失败了，返回默认值
      console.warn(`无法获取联赛${leagueId}的统计信息`)
      return {
        radiantWins: 0,
        direWins: 0,
        totalMatches: 0
      }
      
    } catch (error) {
      console.error('获取联赛统计失败:', error)
      return {
        radiantWins: 0,
        direWins: 0,
        totalMatches: 0
      }
    }
  }

  // 获取联赛比赛 - 使用多数据源策略，优先使用STRATZ API
  async getLeagueMatches(leagueId: number, page: number = 0, pageSize: number = 50): Promise<LeagueMatch[]> {
    try {
      console.log(`获取联赛${leagueId}比赛数据，页面: ${page}, 每页: ${pageSize}`)

      // 策略1: 优先使用STRATZ API获取数据
      console.log(`尝试从STRATZ API获取联赛${leagueId}比赛数据...`)
      const stratzMatches = await this.getLeagueMatchesFromStratz(leagueId, page, pageSize)
      if (stratzMatches.length > 0) {
        console.log(`STRATZ API找到 ${stratzMatches.length} 场比赛`)
        
        // 只对第一页进行缓存，并且获取更多数据用于缓存
        if (page === 0) {
          try {
            // 获取更多数据用于缓存（最多100条，STRATZ API限制）
            const fullMatches = await this.getLeagueMatchesFromStratz(leagueId, 0, 100)
            if (fullMatches.length > 0) {
              cacheManager.setLeagueMatches(leagueId, fullMatches)
              console.log(`联赛${leagueId}比赛数据已缓存，共${fullMatches.length}场比赛`)
            }
          } catch (error) {
            console.warn('缓存联赛比赛数据失败:', error)
          }
        }
        
        return stratzMatches
      }

      // 策略2: 尝试从proMatches获取数据
      console.log(`STRATZ API无结果，尝试从proMatches获取联赛${leagueId}数据...`)
      const proMatchesResponse = await fetch(`${OPENDOTA_API_BASE}/proMatches`)
      if (proMatchesResponse.ok) {
        const proMatches = await proMatchesResponse.json()
        const leagueMatches = proMatches.filter((match: any) => match.leagueid === leagueId)
        
        if (leagueMatches.length > 0) {
          console.log(`proMatches找到 ${leagueMatches.length} 场比赛`)
          // 应用分页逻辑
          const startIndex = page * pageSize
          const endIndex = startIndex + pageSize
          const paginatedMatches = leagueMatches.slice(startIndex, endIndex)
          
          return paginatedMatches.map((match: any) => ({
            match_id: match.match_id,
            start_time: match.start_time,
            duration: match.duration || 0,
            radiant_win: match.radiant_win || false,
            radiant_team: {
              team_id: match.radiant_team_id || 0,
              name: match.radiant_name || 'Unknown Team',
              tag: '',
              logo_url: null
            },
            dire_team: {
              team_id: match.dire_team_id || 0,
              name: match.dire_name || 'Unknown Team',
              tag: '',
              logo_url: null
            },
            radiant_score: match.radiant_score || 0,
            dire_score: match.dire_score || 0
          }))
        }
      }

      // 策略3: 使用explorer API查询matches表
      console.log(`proMatches无结果，尝试explorer API查询联赛${leagueId}...`)
      const offset = page * pageSize
      const sql = `
        SELECT 
          match_id,
          start_time,
          duration,
          radiant_win,
          radiant_team_id,
          dire_team_id,
          radiant_score,
          dire_score,
          leagueid
        FROM matches 
        WHERE leagueid = ${leagueId}
        ORDER BY start_time DESC
        LIMIT ${pageSize}
        OFFSET ${offset}
      `
      
      const encodedSql = encodeURIComponent(sql.trim())
      const explorerResponse = await fetch(`${OPENDOTA_API_BASE}/explorer?sql=${encodedSql}`)
      
      if (explorerResponse.ok) {
        const data = await explorerResponse.json()
        
        if (data.rows && data.rows.length > 0) {
          console.log(`explorer API找到 ${data.rows.length} 场比赛`)
          return data.rows.map((row: any) => ({
            match_id: row.match_id,
            start_time: row.start_time,
            duration: row.duration || 0,
            radiant_win: row.radiant_win || false,
            radiant_team: {
              team_id: row.radiant_team_id || 0,
              name: 'Team ' + (row.radiant_team_id || 'Unknown'),
              tag: '',
              logo_url: null
            },
            dire_team: {
              team_id: row.dire_team_id || 0,
              name: 'Team ' + (row.dire_team_id || 'Unknown'),
              tag: '',
              logo_url: null
            },
            radiant_score: row.radiant_score || 0,
            dire_score: row.dire_score || 0
          }))
        }
      }

      // 如果都没有数据，返回空数组
      console.warn(`所有数据源都无法找到联赛${leagueId}的比赛数据`)
      return []
      
    } catch (error) {
      console.error('获取联赛比赛失败:', error)
      throw error
    }
  }

  // 获取联赛玩家表现排名 - 使用新的Raw Score + Team Multiplier算法
  async getLeaguePlayerRanking(
    leagueId: number, 
    onProgress?: (current: number, total: number, message: string) => void
  ): Promise<LeaguePlayerRanking> {
    // 首先检查缓存
    const cachedRanking = cacheManager.getLeagueRanking(leagueId)
    if (cachedRanking) {
      console.log(`从缓存获取联赛${leagueId}排名数据`)
      onProgress?.(100, 100, '从缓存加载完成')
      return cachedRanking
    }

    try {
      console.log(`获取联赛 ${leagueId} 的玩家表现排名...`)
      onProgress?.(0, 100, '正在获取联赛详情...')
      
      // 动态导入排名算法函数
      const {
        processMatchData,
        calculateMatchRawScore,
        calculatePlayerRawScore,
        DEFAULT_METRIC_WEIGHTS
      } = await import('@/utils/rankingAlgorithm')
      
      // 首先获取联赛详情
      const leagueDetail = await this.getLeagueDetail(leagueId)
      if (!leagueDetail) {
        throw new Error(`无法找到联赛 ${leagueId} 的详情`)
      }

      onProgress?.(10, 100, '正在获取比赛列表...')
      // 获取联赛所有比赛数据
      const allMatches: LeagueMatch[] = []
      const maxMatches = 2000
      const pageSize = 50  // 修改为50，确保不超过STRATZ API的take限制
      const maxPages = Math.ceil(maxMatches / pageSize)
      
      for (let page = 0; page < maxPages; page++) {
        const matches = await this.getLeagueMatches(leagueId, page, pageSize)
        if (matches.length === 0) break
        
        allMatches.push(...matches)
        onProgress?.(10 + (page + 1) * 5 / maxPages, 100, `获取比赛列表 ${page + 1}/${maxPages}...`)
        
        if (matches.length < pageSize) break
      }

      if (allMatches.length === 0) {
        return {
          league_id: leagueId,
          league_name: leagueDetail.name,
          total_players: 0,
          players: [],
          last_updated: Date.now()
        }
      }

      onProgress?.(20, 100, `开始处理 ${allMatches.length} 场比赛的详情...`)
      
      // 限制处理的比赛数量为300场
      const matchesToProcess = allMatches.slice(0, 300)
      const playerMatchData = new Map<string, any[]>() // 存储每个玩家的比赛数据
      const teamEloMap = new Map<number, any>() // 团队Elo评分映射
      const matchDetails: any[] = [] // 存储所有比赛详情
      
      // 使用智能批处理和队列管理
      const batchSize = 6
      const batches = []
      
      for (let i = 0; i < matchesToProcess.length; i += batchSize) {
        batches.push(matchesToProcess.slice(i, i + batchSize))
      }
      
      let processedMatches = 0
      
      // 第一阶段：收集所有比赛数据
      for (let batchIndex = 0; batchIndex < batches.length; batchIndex++) {
        const batch = batches[batchIndex]
        
        const batchPromises = batch.map(async (match, index) => {
          const priority = batchIndex * batchSize + index + 1
          
          return this.stratzRateLimiter.enqueueRequest(async () => {
            const cachedMatch = this.getCachedLeagueMatch(match.match_id.toString())
            if (cachedMatch) {
              return cachedMatch
            }
            
            const matchDetail = await this.getMatchDetailFromStratz(match.match_id.toString())
            this.setCachedLeagueMatch(match.match_id.toString(), matchDetail)
            
            return matchDetail
          }, priority)
        })
        
        try {
          const batchResults = await Promise.all(batchPromises)
          
          batchResults.forEach(matchDetail => {
            if (matchDetail?.players) {
              matchDetails.push(matchDetail)
              
              // 提取团队信息
              const radiantTeam = { team_id: matchDetail.radiant_team?.team_id || 0, team_name: matchDetail.radiant_team?.name || 'Radiant' }
              const direTeam = { team_id: matchDetail.dire_team?.team_id || 0, team_name: matchDetail.dire_team?.name || 'Dire' }
              
              if (!teamEloMap.has(radiantTeam.team_id)) {
                teamEloMap.set(radiantTeam.team_id, radiantTeam)
              }
              if (!teamEloMap.has(direTeam.team_id)) {
                teamEloMap.set(direTeam.team_id, direTeam)
              }
              
              // 计算团队总击杀数
              const radiantKills = matchDetail.players.filter((p: any) => p.player_slot < 128)
                .reduce((sum: number, p: any) => sum + (p.kills || 0), 0)
              const direKills = matchDetail.players.filter((p: any) => p.player_slot >= 128)
                .reduce((sum: number, p: any) => sum + (p.kills || 0), 0)
              
              // 处理每个玩家的数据
              matchDetail.players.forEach((player: any) => {
                if (!player.account_id) return
                
                const playerId = player.account_id.toString()
                const isRadiant = player.player_slot < 128
                const teamKills = isRadiant ? radiantKills : direKills
                const teamId = isRadiant ? radiantTeam.team_id : direTeam.team_id
                const teamName = isRadiant ? radiantTeam.team_name : direTeam.team_name
                const opponentTeamId = isRadiant ? direTeam.team_id : radiantTeam.team_id
                const opponentTeamName = isRadiant ? direTeam.team_name : radiantTeam.team_name
                
                // 处理比赛数据
                const processedMatch = processMatchData({
                  match_id: matchDetail.match_id,
                  duration: matchDetail.duration,
                  win: (isRadiant && matchDetail.radiant_win) || (!isRadiant && !matchDetail.radiant_win),
                  kills: player.kills,
                  deaths: player.deaths,
                  assists: player.assists,
                  hero_damage: player.hero_damage,
                  xpm: player.xp_per_min,
                  gpm: player.gold_per_min,
                  obs_placed: player.obs_placed,
                  sen_placed: player.sen_placed,
                  stuns: player.stuns,
                  hero_healing: player.hero_healing,
                  firstblood_claimed: player.firstblood_claimed,
                  firstblood_given: player.firstblood_given,
                  team_id: teamId,
                  team_name: teamName,
                  opponent_team_id: opponentTeamId,
                  opponent_team_name: opponentTeamName
                }, teamKills)
                
                if (!playerMatchData.has(playerId)) {
                  playerMatchData.set(playerId, [])
                }
                playerMatchData.get(playerId)!.push({
                  ...processedMatch,
                  personaname: player.personaname || `Player ${player.account_id}`
                })
              })
            }
          })
          
          processedMatches += batch.length
          const progress = 20 + (processedMatches / matchesToProcess.length) * 40
          onProgress?.(progress, 100, `已处理 ${processedMatches}/${matchesToProcess.length} 场比赛`)
          
        } catch (error) {
          console.warn(`批次 ${batchIndex + 1} 处理失败:`, error)
        }
      }

      onProgress?.(65, 100, '计算玩家个人表现评分...')
      
      // 直接处理玩家数据，不使用团队Elo系统
      
      onProgress?.(80, 100, '计算玩家Raw Score...')
      
      // 计算每个玩家的Raw Score
      const playerStats = new Map<string, PlayerPerformanceStats>()
      
      for (const [playerId, matches] of playerMatchData.entries()) {
        if (matches.length <= 3) continue // 过滤掉参加3场及以下的选手
        
        // 计算每场比赛的Raw Score
        const processedMatches = matches.map((match: any) => {
          const rawScore = calculateMatchRawScore(match, DEFAULT_METRIC_WEIGHTS)
          match.raw_score = rawScore
          return match
        })
        
        // 计算玩家的平均Raw Score
        const rawScore = calculatePlayerRawScore(processedMatches, DEFAULT_METRIC_WEIGHTS)
        
        // 最终评分直接使用Raw Score，不再使用Team Multiplier
        const finalScore = rawScore
        
        // 计算基础统计数据
        const totalMatches = matches.length
        const wins = matches.filter((m: any) => m.win).length
        const losses = totalMatches - wins
        const winRate = totalMatches > 0 ? wins / totalMatches : 0
        
        // 计算各项平均值
        const totals = matches.reduce((acc: any, match: any) => {
          acc.kills += match.kills || 0
          acc.deaths += match.deaths || 0
          acc.assists += match.assists || 0
          acc.hero_damage += match.hero_damage || 0
          acc.gpm += match.gpm || 0
          acc.xpm += match.xpm || 0
          acc.hero_healing += match.hero_healing || 0
          acc.hero_damage_per_min += match.hero_damage_per_min || 0
          acc.vision_wards_per_min += match.vision_wards_per_min || 0
          acc.crowd_control_per_min += match.crowd_control_per_min || 0
          acc.healing_per_min += match.healing_per_min || 0
          acc.kill_participation += match.kill_participation || 0
          acc.deaths_per_min += match.deaths_per_min || 0
          return acc
        }, {
          kills: 0, deaths: 0, assists: 0, hero_damage: 0, gpm: 0, xpm: 0, hero_healing: 0,
          hero_damage_per_min: 0, vision_wards_per_min: 0, crowd_control_per_min: 0,
          healing_per_min: 0, kill_participation: 0, deaths_per_min: 0
        })
        
        const playerStat: PlayerPerformanceStats = {
          account_id: parseInt(playerId),
          personaname: matches[0].personaname,
          matches_played: totalMatches,
          wins,
          losses,
          win_rate: winRate,
          
          // 总计数据
          total_kills: totals.kills,
          total_deaths: totals.deaths,
          total_assists: totals.assists,
          total_last_hits: 0, // 暂时设为0，因为新算法不使用
          total_denies: 0,
          total_gpm: totals.gpm,
          total_xpm: totals.xpm,
          total_hero_damage: totals.hero_damage,
          total_tower_damage: 0,
          total_hero_healing: totals.hero_healing,
          
          // 平均数据
          avg_kills: totals.kills / totalMatches,
          avg_deaths: totals.deaths / totalMatches,
          avg_assists: totals.assists / totalMatches,
          avg_kda: totals.deaths > 0 ? (totals.kills + totals.assists) / totals.deaths : totals.kills + totals.assists,
          avg_gpm: totals.gpm / totalMatches,
          avg_xpm: totals.xpm / totalMatches,
          avg_last_hits: 0,
          avg_denies: 0,
          avg_hero_damage: totals.hero_damage / totalMatches,
          avg_tower_damage: 0,
          avg_hero_healing: totals.hero_healing / totalMatches,
          
          // 新算法相关字段
          match_performances: processedMatches,
          raw_score: rawScore,
          team_multiplier: 1.0, // 固定为1.0，不再使用团队加成
          final_score: finalScore,
          
          // 新增平均指标
          avg_hero_damage_per_min: totals.hero_damage_per_min / totalMatches,
          avg_vision_wards_per_min: totals.vision_wards_per_min / totalMatches,
          avg_crowd_control_per_min: totals.crowd_control_per_min / totalMatches,
          avg_healing_per_min: totals.healing_per_min / totalMatches,
          avg_kill_participation: totals.kill_participation / totalMatches,
          avg_deaths_per_min: totals.deaths_per_min / totalMatches,
          
          // 兼容字段
          performance_score: Math.round(finalScore * 10) / 10,
          rank: 0
        }
        
        playerStats.set(playerId, playerStat)
      }
      
      onProgress?.(95, 100, '生成最终排名...')
      
      // 按最终评分排序并设置排名
      const players = Array.from(playerStats.values())
        .sort((a, b) => b.final_score - a.final_score)
        .map((stats, index) => {
          stats.rank = index + 1
          return stats
        })

      onProgress?.(100, 100, '排名计算完成')
      
      const rankingResult = {
        league_id: leagueId,
        league_name: leagueDetail.name,
        total_players: players.length,
        players,
        last_updated: Date.now()
      }

      // 将排名数据存储到缓存
      cacheManager.setLeagueRanking(leagueId, rankingResult)
      console.log(`联赛${leagueId}排名数据已缓存，共${players.length}名玩家`)
      
      return rankingResult
      
    } catch (error) {
      console.error('获取联赛玩家排名失败:', error)
      throw error
    }
  }

  // 通用的STRATZ API调用方法
  // 移除未使用的方法
  /*
  private async stratzApiCall<T>(endpoint: string, params: Record<string, any> = {}): Promise<T> {
    const apiKey = getStratzApiToken()
    if (!apiKey) {
      throw new Error('STRATZ API key not found')
    }

    // 使用速率限制管理器
    return this.stratzRateLimiter.enqueueRequest(async () => {
      const url = new URL(`https://api.stratz.com/api/v1/${endpoint}`)
      Object.entries(params).forEach(([key, value]) => {
        if (value !== undefined && value !== null) {
          url.searchParams.append(key, String(value))
        }
      })

      const response = await fetch(url.toString(), {
        headers: {
          'Authorization': `Bearer ${apiKey}`,
          'Content-Type': 'application/json'
        }
      })

      if (response.status === 429) {
        // 429错误时，从响应头获取重试时间
        const retryAfter = response.headers.get('Retry-After')
        const delay = retryAfter ? parseInt(retryAfter) * 1000 : 5000
        console.log(`STRATZ API 429错误，等待 ${delay}ms 后重试`)
        await new Promise(resolve => setTimeout(resolve, delay))
        throw new Error('Rate limit exceeded, will retry')
      }

      if (!response.ok) {
        throw new Error(`STRATZ API error: ${response.status} ${response.statusText}`)
      }

      return response.json()
    }, 1) // 高优先级
  }
  */

  // 获取视野大师排行榜
  async getVisionMasterRanking(
    leagueId: number,
    onProgress?: (current: number, total: number, message: string) => void,
    cachedMatches?: LeagueMatch[],
    cachedLeagueDetail?: LeagueDetail
  ): Promise<VisionMasterRanking> {
    try {
      console.log(`获取联赛 ${leagueId} 的视野大师排行榜...`)
      onProgress?.(0, 100, '正在获取联赛详情...')
      
      // 获取联赛详情 - 优先使用缓存数据
      let leagueDetail: LeagueDetail | null = null
      
      if (cachedLeagueDetail) {
        // 使用缓存的联赛详情
        leagueDetail = cachedLeagueDetail
        onProgress?.(5, 100, '使用缓存的联赛详情')
      } else {
        // 从API获取联赛详情
        leagueDetail = await this.getLeagueDetail(leagueId)
      }
      
      if (!leagueDetail) {
        throw new Error(`无法找到联赛 ${leagueId} 的详情`)
      }

      onProgress?.(10, 100, '正在获取比赛列表...')
      // 获取联赛所有比赛数据 - 优先使用缓存数据
      let allMatches: LeagueMatch[] = []
      
      if (cachedMatches && cachedMatches.length > 0) {
        // 使用缓存的比赛数据
        allMatches = cachedMatches
        onProgress?.(20, 100, `使用缓存的比赛数据 (${allMatches.length} 场比赛)`)
      } else {
        // 从API获取比赛数据
        const maxMatches = 2000
        const pageSize = 50
        const maxPages = Math.ceil(maxMatches / pageSize)
        
        for (let page = 0; page < maxPages; page++) {
          const matches = await this.getLeagueMatches(leagueId, page, pageSize)
          if (matches.length === 0) break
          
          allMatches.push(...matches)
          onProgress?.(10 + (page + 1) * 10 / maxPages, 100, `获取比赛列表 ${page + 1}/${maxPages}...`)
          
          if (matches.length < pageSize) break
        }
      }

      if (allMatches.length === 0) {
        return {
          league_id: leagueId,
          league_name: leagueDetail.name,
          total_players: 0,
          players: [],
          last_updated: Date.now()
        }
      }

      onProgress?.(20, 100, `开始处理 ${allMatches.length} 场比赛的详情...`)
      
      // 限制处理的比赛数量
      const matchesToProcess = allMatches.slice(0, 300)
      const playerStats = new Map<string, {
        account_id: number
        personaname: string
        avatar?: string
        matches_played: number
        total_wards: number
        max_wards_single_match: number
        total_wins: number
        total_losses: number
      }>()
      
      // 使用批处理获取比赛详情
      const batchSize = 6
      const batches = []
      
      for (let i = 0; i < matchesToProcess.length; i += batchSize) {
        batches.push(matchesToProcess.slice(i, i + batchSize))
      }
      
      let processedMatches = 0
      
      for (let batchIndex = 0; batchIndex < batches.length; batchIndex++) {
        const batch = batches[batchIndex]
        
        const batchPromises = batch.map(async (match, index) => {
          const priority = batchIndex * batchSize + index + 1
          
          return this.stratzRateLimiter.enqueueRequest(async () => {
            const cachedMatch = this.getCachedLeagueMatch(match.match_id.toString())
            if (cachedMatch) {
              return cachedMatch
            }
            
            const matchDetail = await this.getMatchDetailFromStratz(match.match_id.toString())
            this.setCachedLeagueMatch(match.match_id.toString(), matchDetail)
            
            return matchDetail
          }, priority)
        })
        
        try {
          const batchResults = await Promise.all(batchPromises)
          
          batchResults.forEach(matchDetail => {
            if (matchDetail?.players) {
              processedMatches++
              
              // 处理每个玩家的视野数据
              matchDetail.players.forEach((player: any) => {
                if (!player.account_id) return
                
                const playerId = player.account_id.toString()
                const isRadiant = player.player_slot < 128
                const won = (isRadiant && matchDetail.radiant_win) || (!isRadiant && !matchDetail.radiant_win)
                
                // 计算插眼总数（真眼 + 假眼）
                const totalWards = (player.obs_placed || 0) + (player.sen_placed || 0)
                
                if (!playerStats.has(playerId)) {
                  playerStats.set(playerId, {
                    account_id: player.account_id,
                    personaname: player.personaname || `Player ${player.account_id}`,
                    avatar: player.avatar,
                    matches_played: 0,
                    total_wards: 0,
                    max_wards_single_match: 0,
                    total_wins: 0,
                    total_losses: 0
                  })
                }
                
                const stats = playerStats.get(playerId)!
                stats.matches_played++
                stats.total_wards += totalWards
                stats.max_wards_single_match = Math.max(stats.max_wards_single_match, totalWards)
                
                if (won) {
                  stats.total_wins++
                } else {
                  stats.total_losses++
                }
              })
            }
          })
          
          const progress = 20 + (batchIndex + 1) * 70 / batches.length
          onProgress?.(progress, 100, `处理比赛详情 ${processedMatches}/${matchesToProcess.length}...`)
          
        } catch (error) {
          console.error(`批次 ${batchIndex} 处理失败:`, error)
        }
      }

      onProgress?.(90, 100, '计算排名...')
      
      // 转换为最终格式并排序
      const players: VisionMasterStats[] = Array.from(playerStats.values())
        .filter(stats => stats.matches_played >= 3) // 至少3场比赛
        .map(stats => ({
          account_id: stats.account_id,
          personaname: stats.personaname,
          avatar: stats.avatar,
          matches_played: stats.matches_played,
          avg_wards_per_match: Number((stats.total_wards / stats.matches_played).toFixed(2)),
          max_wards_single_match: stats.max_wards_single_match,
          win_rate: Number(((stats.total_wins / stats.matches_played) * 100).toFixed(1)),
          total_wins: stats.total_wins,
          total_losses: stats.total_losses
        }))
        .sort((a, b) => b.avg_wards_per_match - a.avg_wards_per_match) // 按平均插眼数降序排列

      onProgress?.(100, 100, '完成')
      
      return {
        league_id: leagueId,
        league_name: leagueDetail.name,
        total_players: players.length,
        players,
        last_updated: Date.now()
      }
      
    } catch (error) {
      console.error('获取视野大师排行榜失败:', error)
      throw error
    }
  }

  // 获取杀戮机器排行榜
  async getKillingMachineRanking(
    leagueId: number,
    onProgress?: (current: number, total: number, message: string) => void,
    cachedMatches?: LeagueMatch[],
    cachedLeagueDetail?: LeagueDetail
  ): Promise<KillingMachineRanking> {
    try {
      console.log(`获取联赛 ${leagueId} 的杀戮机器排行榜...`)
      onProgress?.(0, 100, '正在获取联赛详情...')
      
      // 获取联赛详情 - 优先使用缓存数据
      let leagueDetail: LeagueDetail | null = null
      
      if (cachedLeagueDetail) {
        // 使用缓存的联赛详情
        leagueDetail = cachedLeagueDetail
        onProgress?.(5, 100, '使用缓存的联赛详情')
      } else {
        // 从API获取联赛详情
        leagueDetail = await this.getLeagueDetail(leagueId)
      }
      
      if (!leagueDetail) {
        throw new Error(`无法找到联赛 ${leagueId} 的详情`)
      }

      onProgress?.(10, 100, '正在获取比赛列表...')
      // 获取联赛所有比赛数据 - 优先使用缓存数据
      let allMatches: LeagueMatch[] = []
      
      if (cachedMatches && cachedMatches.length > 0) {
        // 使用缓存的比赛数据
        allMatches = cachedMatches
        onProgress?.(20, 100, `使用缓存的比赛数据 (${allMatches.length} 场比赛)`)
      } else {
        // 从API获取比赛数据
        const maxMatches = 2000
        const pageSize = 50
        const maxPages = Math.ceil(maxMatches / pageSize)
        
        for (let page = 0; page < maxPages; page++) {
          const matches = await this.getLeagueMatches(leagueId, page, pageSize)
          if (matches.length === 0) break
          
          allMatches.push(...matches)
          onProgress?.(10 + (page + 1) * 10 / maxPages, 100, `获取比赛列表 ${page + 1}/${maxPages}...`)
          
          if (matches.length < pageSize) break
        }
      }

      if (allMatches.length === 0) {
        return {
          league_id: leagueId,
          league_name: leagueDetail.name,
          total_players: 0,
          players: [],
          last_updated: Date.now()
        }
      }

      onProgress?.(20, 100, `开始处理 ${allMatches.length} 场比赛的详情...`)
      
      // 限制处理的比赛数量
      const matchesToProcess = allMatches.slice(0, 300)
      const playerStats = new Map<string, {
        account_id: number
        personaname: string
        avatar?: string
        matches_played: number
        total_kills: number
        max_kills_single_match: number
        total_wins: number
        total_losses: number
      }>()
      
      // 使用批处理获取比赛详情
      const batchSize = 6
      const batches = []
      
      for (let i = 0; i < matchesToProcess.length; i += batchSize) {
        batches.push(matchesToProcess.slice(i, i + batchSize))
      }
      
      let processedMatches = 0
      
      for (let batchIndex = 0; batchIndex < batches.length; batchIndex++) {
        const batch = batches[batchIndex]
        
        const batchPromises = batch.map(async (match, index) => {
          const priority = batchIndex * batchSize + index + 1
          
          return this.stratzRateLimiter.enqueueRequest(async () => {
            const cachedMatch = this.getCachedLeagueMatch(match.match_id.toString())
            if (cachedMatch) {
              return cachedMatch
            }
            
            const matchDetail = await this.getMatchDetailFromStratz(match.match_id.toString())
            this.setCachedLeagueMatch(match.match_id.toString(), matchDetail)
            
            return matchDetail
          }, priority)
        })
        
        try {
          const batchResults = await Promise.all(batchPromises)
          
          batchResults.forEach(matchDetail => {
            if (matchDetail?.players) {
              processedMatches++
              
              // 处理每个玩家的击杀数据
              matchDetail.players.forEach((player: any) => {
                if (!player.account_id) return
                
                const playerId = player.account_id.toString()
                const isRadiant = player.player_slot < 128
                const won = (isRadiant && matchDetail.radiant_win) || (!isRadiant && !matchDetail.radiant_win)
                
                const kills = player.kills || 0
                
                if (!playerStats.has(playerId)) {
                  playerStats.set(playerId, {
                    account_id: player.account_id,
                    personaname: player.personaname || `Player ${player.account_id}`,
                    avatar: player.avatar,
                    matches_played: 0,
                    total_kills: 0,
                    max_kills_single_match: 0,
                    total_wins: 0,
                    total_losses: 0
                  })
                }
                
                const stats = playerStats.get(playerId)!
                stats.matches_played++
                stats.total_kills += kills
                stats.max_kills_single_match = Math.max(stats.max_kills_single_match, kills)
                
                if (won) {
                  stats.total_wins++
                } else {
                  stats.total_losses++
                }
              })
            }
          })
          
          const progress = 20 + (batchIndex + 1) * 70 / batches.length
          onProgress?.(progress, 100, `处理比赛详情 ${processedMatches}/${matchesToProcess.length}...`)
          
        } catch (error) {
          console.error(`批次 ${batchIndex} 处理失败:`, error)
        }
      }

      onProgress?.(90, 100, '计算排名...')
      
      // 转换为最终格式并排序
      const players: KillingMachineStats[] = Array.from(playerStats.values())
        .filter(stats => stats.matches_played >= 3) // 至少3场比赛
        .map(stats => ({
          account_id: stats.account_id,
          personaname: stats.personaname,
          avatar: stats.avatar,
          matches_played: stats.matches_played,
          avg_kills_per_match: Number((stats.total_kills / stats.matches_played).toFixed(2)),
          max_kills_single_match: stats.max_kills_single_match,
          win_rate: Number(((stats.total_wins / stats.matches_played) * 100).toFixed(1)),
          total_wins: stats.total_wins,
          total_losses: stats.total_losses
        }))
        .sort((a, b) => b.avg_kills_per_match - a.avg_kills_per_match) // 按平均击杀数降序排列

      onProgress?.(100, 100, '完成')
      
      return {
        league_id: leagueId,
        league_name: leagueDetail.name,
        total_players: players.length,
        players,
        last_updated: Date.now()
      }
      
    } catch (error) {
      console.error('获取杀戮机器排行榜失败:', error)
      throw error
    }
  }
}

export const openDotaAPI = new OpenDotaAPI()
export default openDotaAPI